package com.google.code.mircle.core.transfers;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Enumeration;
import java.util.HashMap;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.google.code.mircle.core.Core;
import com.google.code.mircle.core.View;
import com.google.code.mircle.core.Worker;
import com.google.code.mircle.core.Worker.DownloadState;

public class DirectView extends JPanel implements View, Transfer.Listener {

    final DirectModel model;
    final TransfersPlugin plugin;

    final Core core;

    // Parent: DirectView
    JSplitPane split;

    // Parent: split
    JPanel splitTop = new JPanel(new BorderLayout());

    // Parent: splitTop, Top panel holds toolbar
    JPanel splitTopTop;
    JButton btnStart = new JButton("Start");
    JButton btnStop = new JButton("Stop");
    JButton btnDelete = new JButton("Remove");

    // Parent: splitTop, center panel
    JPanel splitTopCenter;
    JScrollPane splitTopCenterScroll;
    JList splitTopCenterScrollList;

    // Parent: split
    JScrollPane splitDown;

    // Parent: splitDown, holds for ddp or tdp or ydp
    JPanel splitDownPanel = new JPanel();
    DirectDownloadPanel ddp = new DirectDownloadPanel();
    TorrentDownloadPanel tdp = new TorrentDownloadPanel();
    VGetDownloadPanel ydp;

    final long MAX_UPDATE_TIME = 1000;

    public DirectView(Core c, DirectModel s, final TransfersPlugin p) {
        super(new BorderLayout());

        ydp = new VGetDownloadPanel(c, p);

        this.core = c;
        this.plugin = p;
        this.model = s;

        splitTopCenterScrollList = new JList(model.getTransfers());

        final DirectView that = this;

        {
            splitTopTop = new JPanel();

            GridBagLayout gbl_top = new GridBagLayout();
            gbl_top.columnWidths = new int[] { 162, 14, 0, 0, 0, 0 };
            gbl_top.rowHeights = new int[] { 29, 0 };
            gbl_top.columnWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE };
            gbl_top.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
            splitTopTop.setLayout(gbl_top);

            JButton addUrl = new JButton("New Download");
            addUrl.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    NewDownloadDialog dialog = new NewDownloadDialog(core.app, model, that);
                    dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                    dialog.setModal(true);
                    dialog.setLocationRelativeTo(SwingUtilities.getRoot(that));
                    dialog.setVisible(true);
                }
            });

            GridBagConstraints gbc_addUrl = new GridBagConstraints();
            gbc_addUrl.insets = new Insets(0, 0, 0, 5);
            gbc_addUrl.anchor = GridBagConstraints.NORTH;
            gbc_addUrl.gridx = 0;
            gbc_addUrl.gridy = 0;
            splitTopTop.add(addUrl, gbc_addUrl);

            GridBagConstraints gbc_btnStart = new GridBagConstraints();
            gbc_btnStart.insets = new Insets(0, 0, 0, 5);
            gbc_btnStart.gridx = 1;
            gbc_btnStart.gridy = 0;
            btnStart.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    Transfer t = (Transfer) splitTopCenterScrollList.getSelectedValue();
                    model.start(t);
                    core.save(plugin);
                }
            });
            splitTopTop.add(btnStart, gbc_btnStart);

            GridBagConstraints gbc_btnStop = new GridBagConstraints();
            gbc_btnStop.insets = new Insets(0, 0, 0, 5);
            gbc_btnStop.gridx = 2;
            gbc_btnStop.gridy = 0;
            btnStop.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    Transfer t = (Transfer) splitTopCenterScrollList.getSelectedValue();
                    t.stop();
                    core.save(plugin);
                }
            });
            splitTopTop.add(btnStop, gbc_btnStop);

            GridBagConstraints gbc_btnDelete = new GridBagConstraints();
            gbc_btnDelete.insets = new Insets(0, 0, 0, 5);
            gbc_btnDelete.gridx = 3;
            gbc_btnDelete.gridy = 0;
            btnDelete.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    int i = splitTopCenterScrollList.getSelectedIndex();
                    Transfer t = (Transfer) splitTopCenterScrollList.getSelectedValue();
                    model.del(t);
                    if (i >= splitTopCenterScrollList.getModel().getSize())
                        i = splitTopCenterScrollList.getModel().getSize() - 1;
                    splitTopCenterScrollList.setSelectedIndex(i);
                }
            });
            splitTopTop.add(btnDelete, gbc_btnDelete);

            JButton btnNewButton = new JButton("Open");
            btnNewButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    open();
                }
            });
            GridBagConstraints gbc_btnNewButton = new GridBagConstraints();
            gbc_btnNewButton.gridx = 4;
            gbc_btnNewButton.gridy = 0;
            splitTopTop.add(btnNewButton, gbc_btnNewButton);
        }
        splitTop.add(splitTopTop, BorderLayout.NORTH);

        {
            splitTopCenter = new JPanel(new BorderLayout());
            splitTopCenterScrollList.addListSelectionListener(new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent arg0) {
                    updateBottom();
                }
            });
            splitTopCenterScrollList.addMouseListener(new MouseListener() {

                @Override
                public void mouseReleased(MouseEvent arg0) {
                }

                @Override
                public void mousePressed(MouseEvent arg0) {
                }

                @Override
                public void mouseExited(MouseEvent arg0) {
                }

                @Override
                public void mouseEntered(MouseEvent arg0) {
                }

                @Override
                public void mouseClicked(MouseEvent arg0) {
                    if (arg0.getClickCount() == 2) {
                        open();
                    }
                }
            });
            splitTopCenterScroll = new JScrollPane(splitTopCenterScrollList);
            splitTopCenter.add(splitTopCenterScroll);

            splitTop.add(splitTopCenter, BorderLayout.CENTER);
        }

        splitDown = new JScrollPane(splitDownPanel);

        splitDown.setPreferredSize(new Dimension(0, 150));

        split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, splitTop, splitDown);
        split.setResizeWeight(1);

        add(split);

        load();
    }

    public void load() {
        final DirectView that = this;
        final DefaultListModel list = model.getTransfers();

        list.addListDataListener(new ListDataListener() {

            @Override
            public void intervalRemoved(ListDataEvent arg0) {
            }

            @Override
            public void intervalAdded(ListDataEvent e) {
                for (int i = e.getIndex0(); i <= e.getIndex1(); i++) {
                    Transfer t = (Transfer) list.get(i);
                    t.addListener(that);
                }
            }

            @Override
            public void contentsChanged(ListDataEvent arg0) {
            }
        });

        for (Enumeration<?> e = list.elements(); e.hasMoreElements();) {
            Transfer t = (Transfer) e.nextElement();
            t.addListener(this);
        }
    }

    public void close() {
        for (Enumeration<?> e = model.getTransfers().elements(); e.hasMoreElements();) {
            Transfer t = (Transfer) e.nextElement();
            t.removeListener(this);
        }
    }

    void updateBottom() {
        Transfer t = (Transfer) splitTopCenterScrollList.getSelectedValue();
        if (t == null)
            return;

        Worker w = t.getWorker();

        if (w instanceof DirectDownload) {
            ddp.setTransfer(t);

            if (splitDownPanel.getComponentCount() == 0 || !splitDownPanel.getComponent(0).equals(ddp)) {
                splitDownPanel.removeAll();
                splitDownPanel.add(ddp);
                splitDownPanel.revalidate();
                splitDownPanel.repaint();
            }

            DirectDownload dd = (DirectDownload) w;

            btnStart.setEnabled(!t.isAlive() && !(dd.state.downloadState == DownloadState.DOWNLOAD_COMPLETE));
            btnStop.setEnabled(t.isAlive());
            btnDelete.setEnabled(!t.isAlive());
        } else if (w instanceof VGetDownload) {
            ydp.setTransfer(t);

            if (splitDownPanel.getComponentCount() == 0 || !splitDownPanel.getComponent(0).equals(ydp)) {
                splitDownPanel.removeAll();
                splitDownPanel.add(ydp);
                splitDownPanel.revalidate();
                splitDownPanel.repaint();
            }

            VGetDownload y = (VGetDownload) w;
            btnStart.setEnabled(!t.isAlive() && !(y.state.downloadState == DownloadState.DOWNLOAD_COMPLETE));
            btnStop.setEnabled(t.isAlive());
            btnDelete.setEnabled(!t.isAlive());
        } else if (w instanceof TorrentDownload) {
            tdp.setTransfer(t);

            if (splitDownPanel.getComponentCount() == 0 || !splitDownPanel.getComponent(0).equals(tdp)) {
                splitDownPanel.removeAll();
                splitDownPanel.add(tdp);
                splitDownPanel.revalidate();
                splitDownPanel.repaint();
            }

            TorrentDownload dd = (TorrentDownload) w;

            btnStart.setEnabled(!t.isAlive() && !(dd.state.done));
            btnStop.setEnabled(t.isAlive());
            btnDelete.setEnabled(!t.isAlive());
        } else {
            splitDownPanel.removeAll();
            splitDownPanel.revalidate();
            splitDownPanel.repaint();
        }

    }

    public void select(Transfer t) {
        splitTopCenterScrollList.setSelectedValue(t, true);
    }

    @Override
    public void start(Transfer w) {
        update(w);
    }

    @Override
    public void changed(Transfer t) {
        update(t);
    }

    void update(Transfer t) {
        final DefaultListModel list = model.getTransfers();
        int index = list.indexOf(t);

        // TODO: can crash here, if transfer has been deleted and we just
        // receive change event
        Transfer tt = (Transfer) list.get(index);
        list.set(index, tt);

        tt = (Transfer) this.splitTopCenterScrollList.getSelectedValue();
        if (tt != null) {
            if (tt.equals(t))
                updateBottom();
        }
    }

    @Override
    public void stop(Transfer w) {
        update(w);
    }

    void open() {
        Transfer t = (Transfer) splitTopCenterScrollList.getSelectedValue();
        core.player.play(t.getWorker().getTarget());
    }
}
